package com.tbit.uqbike.tergateway.entity;

/**
 * Created by MyWin on 2017/5/11.
 */

import com.alibaba.fastjson.JSONObject;
import com.tbit.uqbike.TerGatewayMain;
import com.tbit.uqbike.protocol.ABaseHandleObj;
import com.tbit.uqbike.protocol.AnalyzeImpl.AAutoProtocol;
import com.tbit.uqbike.protocol.AnalyzeImpl.AProtocol;
import com.tbit.uqbike.service.redis.RedisService;
import com.tbit.uqbike.tergateway.config.TerGatewayConfig;
import com.tbit.uqbike.tergateway.data.TerGatewayData;
import com.tbit.uqbike.tergateway.log.LOG;
import com.tbit.uqbike.tergateway.pojo.OrderStat;
import com.tbit.uqbike.util.ConstDefine;
import com.tbit.uqbike.util.ErrorCode;
import com.tbit.uqbike.util.StringUtil;
import io.netty.buffer.ByteBuf;

import java.util.Date;
import java.util.LinkedList;
import java.util.List;

/**
 * Created by MyWin on 2017/5/10.
 */

public class RemoteControl extends ABaseHandleObj {
    /**
     * 远程控制-上锁
     */
    public final static String CONTROL_TYPE_LOCK = "1";
    /**
     * 远程控制-开锁
     */
    public final static String CONTROL_TYPE_UNLOCK = "11";
    /**
     * 远程控制-撤防
     */
    public final static String CONTROL_TYPE_UNSTART = "2";


    private static org.slf4j.Logger logger = org.slf4j.LoggerFactory.getLogger(RemoteControl.class);
    public String sn;
    public String controlType;
    public String serNO;
    public String paramName;
    public String paramValue;

    /**
     * 是否是离线指令
     */
    public boolean isOfflineOrder = false;
    /**
     * 默认值
     */
    public int iSerNO = Integer.MIN_VALUE;

    public String fromType;
    public String from;
    public int msgId;
    /**
     * 标志终端是否已经回应
     */
    public boolean bTerRsp = false;
    /**
     * 计划下发时间，默认为0
     */
    public Long planDownDt = 0L;

    @Override
    public String toString() {
        return "RemoteControl{" +
                "sn='" + sn + '\'' +
                ", controlType='" + controlType + '\'' +
                ", serNO='" + serNO + '\'' +
                ", paramName='" + paramName + '\'' +
                ", paramValue='" + paramValue + '\'' +
                ", fromType='" + fromType + '\'' +
                ", from='" + from + '\'' +
                ", msgId=" + msgId +
                '}';
    }


    public void buildDownRsp(int code) {
        if (ConstDefine.SYS_IDENT_MQ.equals(fromType)) {
            // 反馈发送结果
            TerControlOrderDownRsp rsp = new TerControlOrderDownRsp();
            rsp.controlRet = Integer.toString(code);
            rsp.serNO = this.serNO;
            TerGatewayMain.getProducer().sendDataToQueue(this.from, toJSONString(StringUtil.Empty, ConstDefine.MQ_MSG_ID_CONTROL_DOWN_RSP, rsp));
        }
    }

    public void buildTerKvRsp(String kv) {
        bTerRsp = true;
        if (ConstDefine.SYS_IDENT_MQ.equals(fromType)) {
            // 反馈发送结果
            TerControlOrderTerRsp rsp = new TerControlOrderTerRsp();
            rsp.paramRet = kv;
            rsp.serNO = this.serNO;
            TerGatewayMain.getProducer().sendDataToQueue(this.from, toJSONString(StringUtil.Empty, ConstDefine.MQ_MSG_ID_CONTROL_TER_RSP, rsp));
        }
        if (isOfflineOrder) {
            // 有结果了更新结果
            TerGatewayMain.getDbService().updateOfflineOrderRspResult(this.serNO, new Date(), null, kv);
            EmptyRedisRecord();
        }
        TerGatewayData.statDataTask.addStatData(TerGatewayConfig.orderDataStatKey, getOrderRspStatMsg(this, kv));
    }

    public void buildTerRetRsp(int ret) {
        bTerRsp = true;
        if (ConstDefine.SYS_IDENT_MQ.equals(fromType)) {
            // 反馈发送结果
            TerControlOrderTerRsp rsp = new TerControlOrderTerRsp();
            rsp.controlRet = Integer.toString(ret);
            rsp.serNO = this.serNO;
            TerGatewayMain.getProducer().sendDataToQueue(this.from, toJSONString(StringUtil.Empty, ConstDefine.MQ_MSG_ID_CONTROL_TER_RSP, rsp));
        }
        if (isOfflineOrder) {
            // 有结果了更新结果
            TerGatewayMain.getDbService().updateOfflineOrderRspResult(this.serNO, new Date(), ret, null);
            EmptyRedisRecord();
        }
        TerGatewayData.statDataTask.addStatData(TerGatewayConfig.orderDataStatKey, getOrderRspStatMsg(this, Integer.toString(ret)));
    }

    private void EmptyRedisRecord() {
        String redisKey = String.format("%s.%s", TerGatewayData.REIDS_ORDER_LIST_TER, sn);
        RedisService redis = TerGatewayMain.getRedis();
        List<String> jsonObjList = redis.LRange(redisKey, 0, -1);
        List<String> delList = new LinkedList<>();
        for (String str : jsonObjList) {
            if (str.contains(this.serNO)) {
                delList.add(str);
            }
        }
        for (String str : delList) {
            redis.LDelValue(redisKey, 0, str);
        }
    }

    /**
     * @param feedback
     * @param msgId
     * @param data
     * @return
     */
    public static String toJSONString(String feedback, int msgId, Object data) {
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("msgId", msgId);
        jsonObject.put("feedback", feedback);
        jsonObject.put("data", data);
        return jsonObject.toJSONString();
    }

    @Override
    public void doBusiness() {
        int code = ErrorCode.ErrorTerOffline;
        try {
            TerTempData terTempData = TerGatewayData.tryGetTerTempDataByMno(this.sn);
            if (null != terTempData) {
                AConnInfo connInfo = terTempData.getConnInfo();
                if (null != connInfo) {
                    AProtocol protocol = AAutoProtocol.getProtocol(terTempData.protocolName);
                    if (null != protocol) {
                        // 再尝试构造下行消息
                        final ByteBuf byteBuf = protocol.builtRemoteControlPkg(connInfo, this);
                        // 最后发送下行数据
                        if (byteBuf != null && byteBuf.readableBytes() > 0) {
                            TerGatewayData.addOrderTimeOutCheck(this);
                            connInfo.downMsg(byteBuf);
                            code = ErrorCode.OK;
                        } else {
                            code = ErrorCode.ErrorDownBufEmpty;
                        }
                    } else {
                        code = ErrorCode.ErrorCtxNotExist;
                    }
                } else {
                    if (LOG.bConnMnoLog) {
                        LOG.NET.info(String.format("get null conn:%s", terTempData.getConnId()));
                    }
                    code = ErrorCode.ErrorConnNotExist;
                }
            }
            this.buildDownRsp(code);
        } catch (Exception e) {
            logger.error("doBusiness", e);
        }
        // 无论成功失败都记录
        TerGatewayData.statDataTask.addStatData(TerGatewayConfig.orderDataStatKey, getOrderStatMsg(this, code));
    }

    public static String getOrderStatMsg(RemoteControl rc, int code) {
        OrderStat os = new OrderStat();
        os.setControlType(rc.controlType);
        os.setControlName(rc.paramName);
        os.setFrom(rc.from);
        os.setProject(TerGatewayConfig.moduleName);
        os.setDt(new Date());
        os.setTo(Integer.toString(code));
        os.setOrderIndent(rc.serNO);
        os.setMno(rc.sn);

        JSONObject jsonObject = new JSONObject();
        jsonObject.put("msgId", ConstDefine.MQ_MSG_ID_ORDER_RECORD);
        jsonObject.put("feedback", StringUtil.Empty);
        jsonObject.put("data", os);
        return jsonObject.toJSONString();
    }

    public static String getOrderRspStatMsg(RemoteControl rc, String rsp) {
        OrderStat os = new OrderStat();
        os.setControlType(rc.controlType);
        os.setControlName(rc.paramName);
        os.setFrom(rc.from);
        os.setProject(TerGatewayConfig.moduleName);
        os.setDt(new Date());
        os.setTo(rc.from);
        os.setOrderIndent(rc.serNO);
        os.setMno(rc.sn);
        os.setRspDt(new Date());
        os.setControlRsp(rsp);

        JSONObject jsonObject = new JSONObject();
        jsonObject.put("msgId", ConstDefine.MQ_MSG_ID_ORDER_RECORD);
        jsonObject.put("feedback", StringUtil.Empty);
        jsonObject.put("data", os);
        return jsonObject.toJSONString();
    }

    public void cloneObj(RemoteControl obj) {
        this.sn = obj.sn;
        this.controlType = obj.controlType;
        this.serNO = obj.serNO;
        this.paramName = obj.paramName;
        this.paramValue = obj.paramValue;
        this.isOfflineOrder = obj.isOfflineOrder;
        this.iSerNO = obj.iSerNO;
        this.fromType = obj.fromType;
        this.from = obj.from;
        this.msgId = obj.msgId;
        this.bTerRsp = obj.bTerRsp;
    }
}
